<!-- eslint-disable vue/multi-word-component-names -->
 <template>
  <div>
    <div style="margin-bottom: 5px; text-align: center;">
      <el-input 
        placeholder="请输入文件名称" 
        :prefix-icon="Search" 
        v-model="name"
        style="width: 200px; margin-left: 5px" 
        @keyup.enter="loadPost()"
      />
      
      <el-button 
        type="success" 
        :icon="Search" 
        circle 
        style="margin-left: 5px;" 
        @click="loadPost()"
        v-if="hasAuth('system:file-search')"
      />
      
      <el-button 
        type="primary" 
        :icon="Refresh" 
        circle 
        style="margin-left: 5px;"
        @click="resetParam()"
      />

      <el-button 
        type="primary" 
        :icon="Plus" 
        circle 
        style="margin-left: 5px;" 
        @click="add()"
        v-if="hasAuth('system:file-save')"
      />
      
      <el-button 
        type="danger" 
        :icon="Delete" 
        circle 
        style="margin-left: 5px;" 
        @click="delHandle(null)"
        v-if="hasAuth('system:file-delete')" 
        :disabled="delBtnStatus"
      />
    </div>
    
    <el-table 
      ref="multipleTableRef" 
      :data="tableData" 
      tooltip-effect="dark" 
      border 
      style="width: 100%" 
      stripe
      @selection-change="handleSelectionChange"
    >
      <el-table-column type="selection" width="55" />
      
      <el-table-column prop="name" label="文件名称" />
      
      <el-table-column prop="url" label="文件展示" width="150">
        <template #default="scope">
          <div v-if="formatFileType(scope.row.type) == '图片'">
            <el-image 
              :src="scope.row.url" 
              style="width: 70px; height: 70px"
              :preview-src-list="[scope.row.url]" 
              fit="cover"
            />
          </div>
          <div v-else-if="formatFileType(scope.row.type) == '视频'">
            <video 
              :src="scope.row.url" 
              controls="controls" 
              style="width: 100px; height: 70px"
            />
          </div>
          <div v-else>
            <el-link type="primary" :href="scope.row.url" target="_blank">点击查看</el-link>
          </div>
        </template>
      </el-table-column>
      
      <el-table-column prop="size" label="文件大小" width="100px">
        <template #default="scope">
          {{ formatFileSize(scope.row.size) }}
        </template>
      </el-table-column>
      
      <el-table-column prop="type" label="文件类型" width="100px">
        <template #default="scope">
          {{ formatFileType(scope.row.type) }}
        </template>
      </el-table-column>
      
      <el-table-column prop="status" label="是否可用" width="150">
        <template #default="scope">
          <el-switch 
            :model-value="scope.row.status == 1" 
            active-color="#13ce66" 
            inactive-color="#ff4949"
            active-text="正常" 
            inactive-text="禁用" 
            @change="modStatus(scope.row.id)"
          />
        </template>
      </el-table-column>
      
      <el-table-column 
        prop="createTime" 
        label="上传时间" 
        width="200" 
        :formatter="formatDate"
      />
      
      <el-table-column fixed="right" label="操作" width="150px" prop="operate">
        <template #default="scope">
          <el-button 
            type="danger" 
            :icon="Delete" 
            circle 
            style="margin-left: 5px;"
            @click="delHandle(scope.row.id)" 
            v-if="hasAuth('system:file-delete')"
          />
        </template>
      </el-table-column>
    </el-table>
    
    <el-pagination 
      @size-change="handleSizeChange" 
      @current-change="handleCurrentChange" 
      :current-page="pageNum"
      :page-size="pageSize" 
      :page-sizes="[5, 10, 50, 100]" 
      background
      layout="total,sizes,prev, pager, next,jumper" 
      :total="total"
    />
    
    <el-dialog 
      v-model="centerDialogVisible" 
      title="文件上传" 
      width="80%" 
      center
    >
      <el-form 
        :model="form" 
        :rules="rules" 
        ref="formRef" 
        label-width="100px"
        style="width: 1200px; margin: 10px auto" 
        enctype="multipart/form-data"
      >
        <el-form-item label="文件" prop="files">
          <div class="upload-container">
            <div 
              class="upload-area" 
              @dragover.prevent 
              @drop.prevent="handleFolderDrop"
              @click="triggerFileInput"
            >
              <el-icon class="upload-icon"><Upload /></el-icon>
              <div class="el-upload__text">将文件或文件夹拖到此处，或<em>点击选择</em></div>
              <div class="el-upload__tip">
                支持多文件上传和文件夹上传，可上传任意类型文件
              </div>
            </div>
            
            <input 
              type="file" 
              ref="fileInputRef" 
              multiple 
              webkitdirectory 
              style="display: none"
              @change="handleFolderSelect" 
            />
            
            <div class="file-list" v-if="fileList.length > 0">
              <div class="file-item" v-for="(file, index) in fileList" :key="index">
                <span class="file-name">{{ file.relativePath || file.name }}</span>
                <span class="file-size">{{ file.size ? formatFileSize(file.size) : '0B' }}</span>
                <el-button 
                  type="danger" 
                  :icon="Delete" 
                  circle
                  @click="removeFile(index)"
                />
              </div>
            </div>
          </div>
        </el-form-item>
      </el-form>
      
      <template #footer>
        <el-button @click="centerDialogVisible = false">取 消</el-button>
        <el-button 
          type="primary" 
          @click="submitUpload" 
          :loading="uploadLoading"
        >
          确 定
        </el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
// eslint-disable-next-line vue/multi-word-component-names
import { ref, reactive, onMounted, computed } from 'vue'
import { 
  Search, 
  Refresh, 
  Plus, 
  Delete, 
  Upload 
} from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Store } from '@/store/index'
import api from '@/axios/index'

// 获取 store 实例
const store = Store()

// refs
const multipleTableRef = ref()
const formRef = ref()
const fileInputRef = ref()

// 数据响应式
const pageSize = ref(5)
const pageNum = ref(1)
const total = ref(0)
const limit = ref(10)
const tableData = ref([])
const delBtnStatus = ref(true)
const centerDialogVisible = ref(false)
const multipleSelection = ref([])
const fileList = ref([])
const uploadLoading = ref(false)
const name = ref("")

const form = reactive({
  id: "",
  name: "",
})

const rules = {
  name: [
    { required: true, message: '文件不能为空', trigger: 'blur' }
  ],
}

// 计算属性
const hasAuth = computed(() => {
  return function (perm) {
    return store.permList.includes(perm)
  }
})

// 方法
// 触发文件选择
const triggerFileInput = () => {
  fileInputRef.value.click()
}

// 处理文件夹选择
const handleFolderSelect = (event) => {
  const files = event.target.files
  processFiles(files)
}

// 处理文件夹拖拽
const handleFolderDrop = (event) => {
  const items = event.dataTransfer.items
  if (items.length > 0) {
    // 处理拖拽的文件或文件夹
    processItems(items)
  }
}

// 处理拖拽项
const processItems = (items) => {
  const files = []
  for (let i = 0; i < items.length; i++) {
    const item = items[i].webkitGetAsEntry()
    if (item) {
      traverseFileTree(item, "", files)
    }
  }

  // 等待所有文件处理完成
  setTimeout(() => {
    fileList.value.push(...files)
  }, 100)
}

// 遍历文件树
const traverseFileTree = (item, path, files) => {
  path = path || ""
  if (item.isFile) {
    // 获取文件
    item.file((file) => {
      // 添加相对路径信息
      file.relativePath = path + file.name
      files.push(file)
    })
  } else if (item.isDirectory) {
    // 获取文件夹内容
    const dirReader = item.createReader()
    dirReader.readEntries((entries) => {
      for (let i = 0; i < entries.length; i++) {
        traverseFileTree(entries[i], path + item.name + "/", files)
      }
    })
  }
}

// 处理文件列表（用于input选择）
const processFiles = (files) => {
  const fileListArray = []
  for (let i = 0; i < files.length; i++) {
    const file = files[i]
    // 保留文件的webkitRelativePath信息
    if (file.webkitRelativePath) {
      file.relativePath = file.webkitRelativePath
    } else {
      file.relativePath = file.name
    }
    fileListArray.push(file)
  }
  fileList.value.push(...fileListArray)
}
const removeFile = (index) => {
  fileList.value.splice(index, 1)
}
const modStatus = (id) => {
    api.post("/file/modStatus/" + id).then((res) => {
        if (res.code == 200) {
            ElMessage({
                message: "修改成功",
                type: "success",
                onClose: () => {
                    loadPost()
                },
            })
        } else {
            ElMessage({
                message: "操作失败！",
                type: "error",
            })
        }
    })
}
const resetParam = () => {
  name.value = ""
}

const formatDate = (row, column) => {
  let data = row[column.property]
  if (data == null) {
    return null
  }
  let dt = new Date(data)
  return (
    dt.getFullYear() +
    "-" +
    (dt.getMonth() + 1) +
    "-" +
    dt.getDate() +
    " " +
    dt.getHours() +
    ":" +
    dt.getMinutes() +
    ":" +
    dt.getSeconds()
  )
}

const formatFileSize = (row) => {
  // 转化文件大小单位
  if (row < 1024) {
    return row + "B"
  } else if (row < 1048576) {
    return (row / 1024).toFixed(2) + "KB"
  } else if (row < 1073741824) {
    return (row / 1048576).toFixed(2) + "MB"
  } else if (row < 1099511627776) {
    return (row / 1073741824).toFixed(2) + "GB"
  } else if (row < 1125899906842624) {
    return (row / 1099511627776).toFixed(2) + "TB"
  } else {
    return (row / 1125899906842624).toFixed(2) + "PB"
  }
}

const formatFileType = (row) => {
  // 传过来的是文件后缀
  switch (row) {
    case "doc":
    case "docx":
      return "word文档"
    case "xls":
    case "xlsx":
      return "excel文档"
    case "ppt":
    case "pptx":
      return "ppt文件"
    case "pdf":
      return "pdf文件"
    case "txt":
      return "txt"
    case "zip":
    case "rar":
      return "压缩文件"
    case "jpg":
    case "jpeg":
    case "png":
    case "gif":
      return "图片"
    case "mp4":
    case "avi":
    case "wmv":
    case "mkv":
      return "视频"
    default:
      return "未知文件"
  }
}

const submitUpload = async () => {
  if (fileList.value.length === 0) {
    ElMessage({
      message: "请至少选择一个文件",
      type: "warning",
    })
    return
  }
  if (fileList.value.length > limit.value) {
    ElMessage({
      message: "最多只能上传" + limit.value + "个文件",
      type: "warning",
    })
    return
  }
  console.log(fileList.value)
  uploadLoading.value = true

  try {
    // 逐个上传文件
    for (let i = 0; i < fileList.value.length; i++) {
      const file = fileList.value[i]

      // 检查是否是文件对象（未上传的文件）
      if (file) {
        await uploadSingleFile(file)
      }
    }

    ElMessage({
      message: "文件上传成功！",
      type: "success",
    })

    centerDialogVisible.value = false
    loadPost()
    resetForm()
  } catch (error) {
    console.error(error)
    ElMessage({
      message: "文件上传失败，请重试",
      type: "error",
    })
  } finally {
    uploadLoading.value = false
  }
}

// 上传单个文件
const uploadSingleFile = (file) => {
  return new Promise((resolve, reject) => {
    const config = {
      headers: {
        "Content-Type": "multipart/form-data",
      },
    }

    let fd = new FormData()
    fd.append("file", file)
    fd.append("name", file.name)

    api.post("/file/upload", fd, config)
      .then((res) => {
        if (res.data.code == 200) {
          resolve(res)
        } else {
          reject(new Error(res.data.msg || "上传失败"))
        }
      })
      .catch((err) => {
        reject(err)
      })
  })
}

const add = () => {
  centerDialogVisible.value = true
  resetForm()
}

const resetForm = () => {
  Object.assign(form, {
    id: "",
    name: "",
  })

  fileList.value = []
}

const handleSizeChange = (val) => {
  console.log(`每页 ${val} 条`)
  pageNum.value = 1
  pageSize.value = val
  loadPost()
}

const handleCurrentChange = (val) => {
  console.log(`当前页: ${val}`)
  pageNum.value = val
  loadPost()
}

const loadPost = () => {
  api.post("/file/listPage", {
    pageSize: pageSize.value,
    pageNum: pageNum.value,
    param: {
      name: name.value,
    },
  })
    .then((res) => {
      console.log(res)
      if (res.code == 200) {
        tableData.value = res.data
        if (res.data.length == 0 && pageNum.value != 1) {
          pageNum.value = 1
          loadPost()
        }
        total.value = res.total
      } else {
        ElMessage({
          message: "数据查询失败",
          type: "warning",
        })
      }
    })
}

const delHandle = (id) => {
  console.log(id)
  var ids = []
  if (id) {
    ids.push(id)
  } else {
    multipleSelection.value.forEach((row) => {
      ids.push(row.id)
    })
  }
  
  ElMessageBox.confirm("将删除文件一切有关数据， 是否继续?", "提示", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  }).then(() => {
    api.post("/file/deleteBatch", ids, {
      headers: {
        "Content-Type": "application/json;charset=UTF-8",
      },
    }).then((res) => {
      console.log(res)
      ElMessage({
        showClose: true,
        message: "恭喜你，操作成功",
        type: "success",
      })
      loadPost()
    }).catch((err) => {
      console.error(err)
      ElMessage({
        showClose: true,
        message: "操作失败，请重试",
        type: "error",
      })
    })
  }).catch(() => {
    ElMessage({
      showClose: true,
      message: "已取消操作",
      type: "info",
    })
  })
}


const handleSelectionChange = (val) => {
  multipleSelection.value = val
  delBtnStatus.value = val.length == 0
}


// 生命周期
onMounted(() => {
  loadPost()
})
</script>

<style scoped>
.el-pagination {
    display: flex;
    justify-content: center;
    margin-top: 20px;
}

.upload-container {
  width: 100%;
}

.upload-area {
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: border-color 0.3s;
  background-color: #fafafa;
  padding: 40px 0;
  text-align: center;
}

.upload-area:hover {
  border-color: #409eff;
}

.upload-icon {
  font-size: 67px;
  color: #c0c4cc;
  margin: 0 auto 10px;
  width: 67px;
  height: 67px;
}

.upload-area .el-upload__text {
  color: #606266;
  font-size: 14px;
  text-align: center;
}

.upload-area .el-upload__text em {
  color: #409eff;
  font-style: normal;
}

.upload-area .el-upload__tip {
  color: #909399;
  font-size: 12px;
  margin-top: 7px;
  text-align: center;
}

.file-list {
  margin-top: 20px;
  max-height: 300px;
  overflow-y: auto;
  border: 1px solid #ebeef5;
  border-radius: 4px;
  padding: 10px;
}

.file-item {
  display: flex;
  justify-content: space-between;
  padding: 8px 0;
  border-bottom: 1px solid #ebeef5;
}

.file-item:last-child {
  border-bottom: none;
}

.file-name {
  flex: 1;
  text-align: left;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  margin-right: 10px;
}

.file-size {
  width: 100px;
  text-align: right;
  color: #909399;
  margin-right: 100px;
}
</style>